package com.sunchangming.stmdb;

import java.util.concurrent.atomic.AtomicLong;

/**
 * ID生成器
 * 
 * @author cm
 * 
 */
public class IDGenerator {
	private volatile AtomicLong[] nextValue;
	static final int typebits = 3;
	static final int serverbits = 12;
	static final int valuebits = Long.SIZE - 1 - typebits - serverbits;

	private static volatile IDGenerator instance;
	private volatile int serverid = 0;

	public void setServerid(int serverid) {
		this.serverid = serverid;
	}

	public static IDGenerator getInstance() {
		if (instance == null) {
			synchronized (IDGenerator.class) {
				if (instance == null)
					instance = new IDGenerator();
			}
		}
		return instance;
	}

	public static interface IType {
		/** 类型，如0代表角色，1代表宠物，2代表物品。 */
		int getId();

		/** 当前的最大值。只要底层的存储引擎不是Hash而是采用Btree这样的，那么这个值很容易拿到 */
		long getMaxValue();
	}

	private IDGenerator() {
		final int maxlen = getMaxTypeId() + 1;
		nextValue = new AtomicLong[maxlen];
	}

	static private int getMaxTypeId() {
		return (1 << typebits) - 1;
	}

	private static long getNextidFromCurrentValue(long value) {
		return ((value & (((1 << valuebits) - 1) << serverbits)) >> serverbits + 1);
	}

	/**
	 * server每次启动的时候调一下这个方法
	 * 
	 * @param type
	 */
	public synchronized void register(IType type) {
		if (type.getId() > getMaxTypeId())
			throw new IllegalArgumentException("错误。type id 太大");
		nextValue[type.getId()] = new AtomicLong(getNextidFromCurrentValue(type.getMaxValue()));
	}

	/**
	 * 生成下一个值 XXX:如果保证nextValue[type]不为空？volatile修饰的是nextValue？
	 * 
	 * @param type
	 * @return
	 */
	public long getNextValue(int type) {
		final long v1 = type << (serverbits + valuebits);
		final long v2 = (nextValue[type].incrementAndGet()) << serverbits;
		return v1 | v2 | this.serverid;
	}
}
